package io.github.rascaler.dcenter.config;

import io.github.rascaler.dcenter.context.ResponseBodyWrapHandler;
import io.github.rascaler.dcenter.exception.BizException;
import io.github.rascaler.dcenter.exception.GlobalWebExceptionHandlerBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import io.github.rascaler.assertj.Assertions;
import io.github.rascaler.assertj.core.exception.ExceptionConvertor;


@Configuration
@Slf4j
public class MvcConfig {

    public MvcConfig() {
        Assertions.addExceptionConvertor(new BizExceptionConvertor());
    }

    public class BizExceptionConvertor implements ExceptionConvertor<String, BizException> {
        @Override
        public BizException getException(String code) {
            return new BizException(code);
        }
    }

    /**
     * 实例化自定义返回值处理器
     * <p>如果担心RequestMappingHandlerAdapter未实例化完成
     * 可添加@DependsOn("requestMappingHandlerAdapter")，
     * 但是测试后发现不需要</p>
     * @return
     */
    @Bean
    public ResponseBodyWrapHandler apiResponseBodyReturnValueHandler(RequestMappingHandlerAdapter adapter) {

        List<HandlerMethodReturnValueHandler> returnValueHandlers = adapter.getReturnValueHandlers();
        // 1.new个新的集合（必须要new，否则报错；这个是关键, 因为上面的那个list是个不可修改的集合），把所有的returnValueHandlers 装进去
        List<HandlerMethodReturnValueHandler> newHandlerList = new ArrayList<>(returnValueHandlers);
        // 2.通过反射获取 获取 request和response advice(主要目的是为了支持RequestAdvice和ResponseAdvice，如果不用，可以考虑不获取)
        List<Object> requestResponseBodyAdvice = getAdviceWithReflect(adapter);
        // 3.实例化，这里从adapter里面取消息转换器
        ResponseBodyWrapHandler handler = new ResponseBodyWrapHandler(adapter.getMessageConverters(), requestResponseBodyAdvice);
        // 3.把自定义的handler添加到handlerList中的首位
        newHandlerList.add(0, handler);
        // 4.替换RequestMappingHandlerAdapter中的ReturnValueHandlers
        adapter.setReturnValueHandlers(newHandlerList);
        return handler;
    }

    @Bean
    @ConditionalOnMissingBean(name = "globalWebExceptionHandlerBean")
    public GlobalWebExceptionHandlerBean globalWebExceptionHandlerBean() {
        log.info("[immune-framework-web] GlobalWebExceptionHandlerBean...Have started");
        return new GlobalWebExceptionHandlerBean();
    }




    /**
     * description: 暴力反射后期RequestMappingHandlerAdapter中的requestResponseBodyAdvice
     * @param adapter
     * @return java.util.List<java.lang.Object>
     * @author ZENG.XIAO.YAN
     * @time 2020-06-19 17:27
     */
    private List<Object> getAdviceWithReflect(RequestMappingHandlerAdapter adapter) {
        try {
            Field field = RequestMappingHandlerAdapter.class.getDeclaredField("requestResponseBodyAdvice");
            field.setAccessible(true);
            Object obj = field.get(adapter);
            return (List<Object>) obj;
        } catch (Exception e) {
            log.error("反射获取requestResponseBodyAdvice异常", e);
        }
        return new ArrayList<>();
    }

}

